﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using YArchitech.LIB;
using QuickModel.Forms;
using QuickModel.QuickModelFrame;

namespace QuickModel
{
	public class QuickModelFrameWork : IQuickModel
	{
		public QuickModelFrameWork(IRequestMaker useRequestMaker, IResponseHanlder useResponseHanlder)
		{
			this.m_useRequestMaker = useRequestMaker;
			this.m_lstGrouperType = this.GetTypesInAssembly<IDataGrouper>();
			this.m_lstBuilderType = this.GetTypesInAssembly<IRevitModelRebuilder>();
			this.m_useResponseHanlder = useResponseHanlder;
			this.PrepareMap<IDataGrouper, GrouperAttribute>(this.m_lstGrouperType, this.m_dicUSeGropuerMap);
			this.PrepareMap<IRevitModelRebuilder, RebuilderAttribute>(this.m_lstBuilderType, this.m_dicUseRebuilderMap);
		}

		public void Excute(ExternalCommandData inputCommandData)
		{
			Document document = inputCommandData.Application.ActiveUIDocument.Document;
			this.WorkHanlder(inputCommandData, document);
		}

		public void ExcuteWithWhile(ExternalCommandData inputCommandData)
		{
			Document document = inputCommandData.Application.ActiveUIDocument.Document;
			for (;;)
			{
				try
				{
					this.WorkHanlder(inputCommandData, document);
					bool ifEndCommand = this.m_useRequestMaker.IfEndCommand;
					if (ifEndCommand)
					{
						this.m_useRequestMaker.CloseFrom();
						break;
					}
				}
				catch (Autodesk.Revit.Exceptions.OperationCanceledException)
				{
					bool ifBreak = this.m_useRequestMaker.IfBreak;
					if (ifBreak)
					{
						this.m_useRequestMaker.CloseFrom();
						break;
					}
				}
			}
		}

		private void WorkHanlder(ExternalCommandData inputCommandData, Autodesk.Revit.DB.Document useDoc)
		{
			using (TransactionGroup transactionGroup = new TransactionGroup(useDoc, "uiGroup"))
			{
				try
				{
					transactionGroup.Start();
					this.m_useRequestMaker.PrepareRequest();
					bool ifCancel = this.m_useRequestMaker.IfCancel;
					if (ifCancel)
					{
						transactionGroup.RollBack();
						return;
					}
					transactionGroup.Assimilate();
				}
				catch (Exception ex)
				{
					bool flag = transactionGroup.HasStarted();
					if (flag)
					{
						transactionGroup.RollBack();
					}
					throw ex;
				}
			}
			bool flag2 = this.m_useResponseHanlder != null;
			if (flag2)
			{
				this.m_useResponseHanlder.AddStartTime(DateTime.Now);
			}
			List<InputRequest> allInputRequest = this.m_useRequestMaker.GetAllInputRequest();
			List<RevitModelRequest> lstRevitModelRequest = new List<RevitModelRequest>();
			QuickModelProgressBar quickModelProgressBar = new QuickModelProgressBar(null);
			bool flag3 = this.Group(inputCommandData, allInputRequest, lstRevitModelRequest, quickModelProgressBar);
			bool flag4 = flag3;
			if (!flag4)
			{
				List<RevitModelRebuildResponse> list = new List<RevitModelRebuildResponse>();
				bool flag5 = this.ReBuild(useDoc, lstRevitModelRequest, list, quickModelProgressBar);
				bool flag6 = flag5;
				if (!flag6)
				{
					bool flag7 = !quickModelProgressBar.IsDisposed;
					if (flag7)
					{
						quickModelProgressBar.Dispose();
					}
					bool flag8 = this.m_useResponseHanlder != null;
					if (flag8)
					{
						this.m_useResponseHanlder.AddEndTime(DateTime.Now);
						foreach (RevitModelRebuildResponse inputResponse in list)
						{
							this.m_useResponseHanlder.AddOneResponse(inputResponse);
						}
						this.m_useResponseHanlder.HanlderResponse();
					}
				}
			}
		}

		private List<Type> GetTypesInAssembly<T>()
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			Type baseType = typeof(T);
			IEnumerable<Type> source = from n in executingAssembly.GetTypes()
			where baseType.IsAssignableFrom(n)
			select n;
			return source.ToList<Type>();
		}

		private bool Autodesk.Revit.DB.Group(ExternalCommandData inputCommandData, List<InputRequest> lstInputRequest, List<RevitModelRequest> lstRevitModelRequest, QuickModelProgressBar inputProcessBar)
		{
			bool result;
			try
			{
				inputProcessBar.SetSubMaxValue(lstInputRequest.Count);
				bool flag = false;
				Process currentProcess = Process.GetCurrentProcess();
				IntPtr mainWindowHandle = currentProcess.MainWindowHandle;
				YJKWindowHandle owner = new YJKWindowHandle(mainWindowHandle);
				inputProcessBar.Show(owner);
				string text = string.Empty;
				foreach (InputRequest inputRequest in lstInputRequest)
				{
					bool isDisposed = inputProcessBar.IsDisposed;
					if (isDisposed)
					{
						flag = true;
						break;
					}
					text = ProgressBarAttribute.GetAttributeText(inputRequest);
					text = (string.IsNullOrWhiteSpace(text) ? "正在识别" : string.Format("正在识别{0}", text));
					inputProcessBar.RefreshProgressBarText(text);
					inputRequest.UseExternalCommandData = inputCommandData;
					string hanlderName = this.GetHanlderName<GrouperAttribute>(inputRequest);
					bool flag2 = string.IsNullOrWhiteSpace(hanlderName) || !this.m_dicUSeGropuerMap.ContainsKey(hanlderName);
					if (!flag2)
					{
						List<RevitModelRequest> list = this.m_dicUSeGropuerMap[hanlderName].GroupData(inputRequest);
						bool flag3 = list == null;
						if (!flag3)
						{
							foreach (RevitModelRequest revitModelRequest in list)
							{
								revitModelRequest.UseCadLocationKind = inputRequest.UseCadLocationKind;
								revitModelRequest.UseExternalCommandData = inputRequest.UseExternalCommandData;
								revitModelRequest.UseTypeName = inputRequest.UseTypeName;
								revitModelRequest.UseRevitLocationKind = inputRequest.UseRevitLocationKind;
								lstRevitModelRequest.Add(revitModelRequest);
							}
							bool isDisposed2 = inputProcessBar.IsDisposed;
							if (isDisposed2)
							{
								flag = true;
								break;
							}
							inputProcessBar.RefreshProgressBar(text);
						}
					}
				}
				result = flag;
			}
			catch (Exception ex)
			{
				bool flag4 = inputProcessBar != null && !inputProcessBar.IsDisposed;
				if (flag4)
				{
					inputProcessBar.Close();
				}
				result = true;
			}
			return result;
		}

		private bool ReBuild(Autodesk.Revit.DB.Document useDoc, List<RevitModelRequest> lstRevitModelRequest, List<RevitModelRebuildResponse> lstUseResponse, QuickModelProgressBar useProgressBar)
		{
			useProgressBar.SetSubMaxValue(lstRevitModelRequest.Count);
			bool flag = false;
			TransactionGroup transactionGroup = new TransactionGroup(useDoc, "quickModel");
			Transaction transaction = null;
			RevitModelRequest revitModelRequest = null;
			string text = string.Empty;
			try
			{
				transactionGroup.Start();
				List<WorkAfterRegenernateDel> list = new List<WorkAfterRegenernateDel>();
				foreach (RevitModelRequest revitModelRequest2 in lstRevitModelRequest)
				{
					bool isDisposed = useProgressBar.IsDisposed;
					if (isDisposed)
					{
						flag = true;
						break;
					}
					text = ProgressBarAttribute.GetAttributeText(revitModelRequest2);
					text = (string.IsNullOrWhiteSpace(text) ? "正在转换" : string.Format("正在转换{0}", text));
					useProgressBar.RefreshProgressBarText(text);
					this.DoWorkForRegenerate(useDoc, revitModelRequest, list, ref transaction, revitModelRequest2);
					revitModelRequest = revitModelRequest2;
					transaction = this.PrepareTransaction(useDoc, revitModelRequest, transaction);
					RevitModelRebuildResponse revitModelRebuildResponse = new RevitModelRebuildResponse();
					revitModelRebuildResponse.UseRequest = revitModelRequest2;
					string hanlderName = this.GetHanlderName<RebuilderAttribute>(revitModelRequest2);
					bool flag2 = string.IsNullOrWhiteSpace(hanlderName) || !this.m_dicUseRebuilderMap.ContainsKey(hanlderName);
					if (flag2)
					{
						revitModelRebuildResponse.IfSucess = false;
					}
					else
					{
						BuildData buildData = null;
						IRevitModelRebuilder revitModelRebuilder = this.m_dicUseRebuilderMap[hanlderName];
						try
						{
							revitModelRebuildResponse.IfSucess = revitModelRebuilder.TryRebuildRevitModel(useDoc, revitModelRequest2, out buildData);
							revitModelRebuildResponse.ThisBuildData = buildData;
							bool flag3 = buildData != null && buildData.UseWork != null;
							if (flag3)
							{
								list.Add(buildData.UseWork);
							}
						}
						catch (Exception)
						{
							revitModelRebuildResponse.IfSucess = false;
							revitModelRebuildResponse.ThisBuildData = null;
						}
					}
					lstUseResponse.Add(revitModelRebuildResponse);
					bool isDisposed2 = useProgressBar.IsDisposed;
					if (isDisposed2)
					{
						flag = true;
						break;
					}
					useProgressBar.RefreshProgressBar(text);
				}
				bool flag4 = flag;
				if (flag4)
				{
					this.RollBackTransaction(transactionGroup, transaction);
					return flag;
				}
				bool flag5 = transaction != null;
				if (flag5)
				{
					transaction = this.CommitTransaction(transaction);
				}
				this.DoDelWork(useDoc, list, revitModelRequest);
				transactionGroup.Assimilate();
			}
			catch (Exception)
			{
				bool flag6 = useProgressBar != null && !useProgressBar.IsDisposed;
				if (flag6)
				{
					useProgressBar.Close();
				}
				this.RollBackTransaction(transactionGroup, transaction);
				foreach (RevitModelRebuildResponse revitModelRebuildResponse2 in lstUseResponse)
				{
					revitModelRebuildResponse2.IfSucess = false;
					revitModelRebuildResponse2.ThisBuildData = null;
				}
			}
			return flag;
		}

		private void RollBackTransaction(TransactionGroup useTransactionGroup, Transaction tempTransaction)
		{
			bool flag = tempTransaction != null && tempTransaction.HasStarted();
			if (flag)
			{
				tempTransaction.RollBack();
			}
			bool flag2 = useTransactionGroup.HasStarted();
			if (flag2)
			{
				useTransactionGroup.RollBack();
			}
		}

		private Transaction PrepareTransaction(Autodesk.Revit.DB.Document useDoc, RevitModelRequest tempRequest, Transaction tempTransaction)
		{
			RebuilderTransactionAttribute rebuilderTransactionAttribute = tempRequest.GetType().GetCustomAttribute(this.m_useTransactionAttribute) as RebuilderTransactionAttribute;
			bool flag = tempTransaction == null && rebuilderTransactionAttribute != null && !string.IsNullOrWhiteSpace(rebuilderTransactionAttribute.UseTransactionName);
			if (flag)
			{
				tempTransaction = this.StratTransaction(useDoc, rebuilderTransactionAttribute);
			}
			else
			{
				bool flag2 = tempTransaction != null;
				if (flag2)
				{
					bool flag3 = rebuilderTransactionAttribute == null || string.IsNullOrWhiteSpace(rebuilderTransactionAttribute.UseTransactionName);
					if (flag3)
					{
						tempTransaction = this.CommitTransaction(tempTransaction);
					}
					else
					{
						bool flag4 = rebuilderTransactionAttribute != null && !tempTransaction.GetName().Equals(rebuilderTransactionAttribute.UseTransactionName);
						if (flag4)
						{
							tempTransaction = this.CommitTransaction(tempTransaction);
							tempTransaction = this.StratTransaction(useDoc, rebuilderTransactionAttribute);
						}
					}
				}
			}
			return tempTransaction;
		}

		private Transaction StratTransaction(Autodesk.Revit.DB.Document useDoc, RebuilderTransactionAttribute tempAtttribute)
		{
			Transaction transaction = new Transaction(useDoc, tempAtttribute.UseTransactionName);
			try
			{
				transaction.Start();
			}
			catch (Exception ex)
			{
				transaction = null;
			}
			return transaction;
		}

		private Transaction CommitTransaction(Transaction tempTransaction)
		{
			try
			{
				tempTransaction.Commit();
			}
			catch (Exception ex)
			{
				bool flag = tempTransaction.HasStarted();
				if (flag)
				{
					tempTransaction.RollBack();
				}
			}
			finally
			{
				tempTransaction = null;
			}
			return tempTransaction;
		}

		private void DoWorkForRegenerate(Autodesk.Revit.DB.Document useDoc, RevitModelRequest tempRequest, List<WorkAfterRegenernateDel> lstTempDel, ref Transaction tempTransaction, RevitModelRequest oneRebuildeRequest)
		{
			bool flag = tempRequest != null && tempRequest.GetType() != oneRebuildeRequest.GetType();
			if (flag)
			{
				bool flag2 = (lstTempDel.Count != 0 || oneRebuildeRequest.IfNeedRegenerate) && tempTransaction != null && tempTransaction.HasStarted();
				if (flag2)
				{
					tempTransaction = this.CommitTransaction(tempTransaction);
				}
				this.DoDelWork(useDoc, lstTempDel, tempRequest);
				bool ifNeedRegenerate = oneRebuildeRequest.IfNeedRegenerate;
				if (ifNeedRegenerate)
				{
					this.RegenerateDoc(useDoc);
				}
			}
		}

		private void DoDelWork(Autodesk.Revit.DB.Document useDoc, List<WorkAfterRegenernateDel> lstTempDel, RevitModelRequest useRequest = null)
		{
			bool flag = lstTempDel.Count != 0;
			if (flag)
			{
				this.RegenerateDoc(useDoc);
				Transaction transaction = null;
				bool flag2 = useRequest != null;
				if (flag2)
				{
					RebuildRequestDelegateTransactionAttribute rebuildRequestDelegateTransactionAttribute = useRequest.GetType().GetCustomAttribute(typeof(RebuildRequestDelegateTransactionAttribute)) as RebuildRequestDelegateTransactionAttribute;
					bool flag3 = rebuildRequestDelegateTransactionAttribute != null && !string.IsNullOrWhiteSpace(rebuildRequestDelegateTransactionAttribute.UseTransactionName);
					if (flag3)
					{
						transaction = new Transaction(useDoc, rebuildRequestDelegateTransactionAttribute.UseTransactionName);
					}
				}
				try
				{
					bool flag4 = transaction != null;
					if (flag4)
					{
						transaction.Start();
					}
					foreach (WorkAfterRegenernateDel workAfterRegenernateDel in lstTempDel)
					{
						workAfterRegenernateDel();
					}
					bool flag5 = transaction != null;
					if (flag5)
					{
						transaction.Commit();
					}
				}
				catch (Exception ex)
				{
					bool flag6 = transaction != null && transaction.HasStarted();
					if (!flag6)
					{
						throw ex;
					}
					transaction.RollBack();
				}
				lstTempDel.Clear();
			}
		}

		private void RegenerateDoc(Autodesk.Revit.DB.Document inputDoc)
		{
			Transaction transaction = new Transaction(inputDoc, "RegenerateDoc");
			try
			{
				transaction.Start();
				inputDoc.Regenerate();
				transaction.Commit();
			}
			catch (Exception)
			{
				bool flag = transaction.HasStarted();
				if (flag)
				{
					transaction.RollBack();
				}
			}
			finally
			{
			}
		}

		private string GetHanlderName<X>(object inputObj) where X : class, IUseHandlerNameGeter
		{
			string text = null;
			Type type = inputObj.GetType();
			X x = type.GetCustomAttribute(typeof(X)) as X;
			bool flag = x == null;
			string result;
			if (flag)
			{
				result = text;
			}
			else
			{
				text = x.UseHanlderName();
				result = text;
			}
			return result;
		}

		private void PrepareMap<T, X>(List<Type> lstInputGrouperType, Dictionary<string, T> useMap) where T : class where X : IUseHandlerNameGeter
		{
			Type typeFromHandle = typeof(T);
			foreach (Type type in lstInputGrouperType)
			{
				bool flag = !typeFromHandle.IsAssignableFrom(type);
				if (!flag)
				{
					IUseHandlerNameGeter useHandlerNameGeter = type.GetCustomAttribute(typeof(X)) as IUseHandlerNameGeter;
					bool flag2 = useHandlerNameGeter == null;
					if (!flag2)
					{
						string text = useHandlerNameGeter.UseHanlderName();
						bool flag3 = string.IsNullOrWhiteSpace(text) || useMap.ContainsKey(text);
						if (!flag3)
						{
							T value = default(T);
							try
							{
								value = (Activator.CreateInstance(type) as T);
								useMap.Add(text, value);
							}
							catch (Exception)
							{
							}
						}
					}
				}
			}
		}

		private IRequestMaker m_useRequestMaker;

		private List<Type> m_lstGrouperType;

		private List<Type> m_lstBuilderType;

		private IResponseHanlder m_useResponseHanlder;

		private Dictionary<string, IDataGrouper> m_dicUSeGropuerMap = new Dictionary<string, IDataGrouper>();

		private Dictionary<string, IRevitModelRebuilder> m_dicUseRebuilderMap = new Dictionary<string, IRevitModelRebuilder>();

		private Type m_useTransactionAttribute = typeof(RebuilderTransactionAttribute);
	}
}
